package com.tian.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.tian.common.CommonResult;
import com.tian.dto.MessageTemplateDto;
import com.tian.dto.SendCodeReqDto;
import com.tian.enums.ResultCode;
import com.tian.message.SmsSendMessage;
import com.tian.producer.SmsProducer;
import com.tian.service.MessageTemplateService;
import com.tian.service.SendCodeService;
import com.tian.util.LimiterUtil;
import com.tian.util.RedisConstantPre;
import com.tian.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @author tianwc  公众号：java后端技术全栈、面试专栏
 * @version 1.0.0
 * 博客地址：<a href="http://woaijava.cc/">博客地址</a>
 * <p>
 * 发送验证码
 */
@Slf4j
@Service
public class SendCodeServiceImpl implements SendCodeService {
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private MessageTemplateService messageTemplateService;
    @Resource
    private LimiterUtil limiterUtil;
    @Resource
    private SmsProducer smsProducer;

    @Override
    public CommonResult<Boolean> sendCode(SendCodeReqDto sendCodeReqDto) {
        String phone = sendCodeReqDto.getPhone();
        int msgTemplateId = sendCodeReqDto.getMsgTemplateId();

        if (StringUtil.isEmpty(phone)) {
            return CommonResult.failed(ResultCode.VALIDATE_FAILED);
        }
        boolean limit = limiterUtil.slidingWindow(RedisConstantPre.MESSAGE_LIMIT_KEY_PRE + phone, 60L, RateIntervalUnit.SECONDS, 5);
        if (limit) {
            return CommonResult.failed(ResultCode.SEND_MESSAGE_LIMIT);
        }
        CommonResult<MessageTemplateDto> commonResult = messageTemplateService.queryByMessageType(msgTemplateId);
        if (commonResult.getCode() != ResultCode.SUCCESS.getCode()) {
            log.error("短信模板不存在，msgTemplateId={}", msgTemplateId);
            return CommonResult.failed(ResultCode.VALIDATE_FAILED);
        }

        MessageTemplateDto messageTemplateDto = commonResult.getData();

        String code = RandomUtil.randomNumbers(6);
        log.info("发送验证码：{}", code);
        String template = messageTemplateDto.getTemplate();
        LinkedHashMap<String, String> params = new LinkedHashMap<>();
        params.put("code", code);
        SmsSendMessage smsSendMessage = new SmsSendMessage();
        smsSendMessage.setParams(params);
        smsSendMessage.setPhone(phone);
        smsSendMessage.setCacheKeyPre(RedisConstantPre.SEND_CODE_PRE);
        smsSendMessage.setMsgTemplate(template);
        smsProducer.send(smsSendMessage);
        RBucket<String> bucket = redissonClient.getBucket(RedisConstantPre.SEND_CODE_PRE + phone);
        bucket.set(code, 60, TimeUnit.SECONDS);
        return CommonResult.success(Boolean.TRUE);
    }

    @Override
    public CommonResult<Boolean> codeValid(String phone, String code) {

        if (StringUtil.isEmpty(phone) || StringUtil.isEmpty(code)) {
            return CommonResult.failed(ResultCode.VALIDATE_FAILED);
        }

        String key = RedisConstantPre.SEND_CODE_PRE + phone;

        RBucket<String> bucket= redissonClient.getBucket(key);
        String codeCache = bucket.get();
        if (StringUtil.isEmpty(codeCache)) {
            return CommonResult.failed(ResultCode.VALIDATE_FAILED);
        }

        if (!code.equals(codeCache)) {
            boolean limit = limiterUtil.slidingWindow(key, 60000L, RateIntervalUnit.SECONDS, 5);
            if (limit) {
                return CommonResult.failed(ResultCode.SEND_MESSAGE_LIMIT);
            }
        }
        return CommonResult.success(Boolean.TRUE);
    }
}

